﻿using Opc.Ua;
using Opc.Ua.Server;
using SD.OpcServer.Host.Variables;
using System.Collections.Generic;
using System.Linq;

namespace SD.OpcServer.Host.Hosts
{
    /// <summary>
    /// 节点管理器
    /// </summary>
    public class NodeManager : CustomNodeManager2
    {
        /// <summary>
        /// OPC变量组列表
        /// </summary>
        private readonly ICollection<OpcVariableGroup> _variableGroups;

        /// <summary>
        /// 创建节点管理器构造器
        /// </summary>
        public NodeManager(IServerInternal server, ApplicationConfiguration configuration, IEnumerable<OpcVariableGroup> variableGroups)
            : base(server, configuration, Namespaces.OpcUa)
        {
            //初始化
            this._variableGroups = new HashSet<OpcVariableGroup>();

            variableGroups = variableGroups?.ToArray() ?? new OpcVariableGroup[0];
            foreach (OpcVariableGroup variableGroup in variableGroups)
            {
                this._variableGroups.Add(variableGroup);
            }

            base.SystemContext.NodeIdFactory = this;
        }

        /// <summary>
        /// 创建地址空间
        /// </summary>
        public override void CreateAddressSpace(IDictionary<NodeId, IList<IReference>> externalReferences)
        {
            lock (base.Lock)
            {
                base.LoadPredefinedNodes(base.SystemContext, externalReferences);

                if (!externalReferences.TryGetValue(ObjectIds.ObjectsFolder, out IList<IReference> references))
                {
                    references = new List<IReference>();
                    externalReferences[ObjectIds.ObjectsFolder] = references;
                }

                foreach (OpcVariableGroup variableGroup in this._variableGroups)
                {
                    variableGroup.AddReference(ReferenceTypes.Organizes, true, ObjectIds.ObjectsFolder);
                    references.Add(new NodeStateReference(ReferenceTypes.Organizes, false, variableGroup.NodeId));
                    variableGroup.EventNotifier = EventNotifiers.SubscribeToEvents;
                    variableGroup.NodeManager = this;

                    base.AddRootNotifier(variableGroup);
                    base.AddPredefinedNode(base.SystemContext, variableGroup);
                }
            }
        }
    }
}
